//============================================================================
// Copyright (C) 2009Brett R. Jones
//
// Issued to public domain 2013
//
// brettjones1900@gmail.com
// http://www.p2panarchy.com
//============================================================================

#include <stdarg.h>
#include <stdio.h>
#include <string>
#include <string.h>

#ifdef WIN_PLATFORM
	#include <WinSock2.h>
	#include "windows.h"
#endif // WIN_PLATFORM
#ifdef ANDROID_PLATFORM
	#include <android/log.h>
	#include <unistd.h>
#endif // WIN_PLATFORM

#include "vx_debug.h"
#include <VxUtilLib/VxMutex.h>
#include <VxUtilLib/VxGlobals.h>
#include <VxUtilLib/VxFileUtil.h>

#ifdef WIN_PLATFORM
    #pragma warning( disable: 4996 )
#endif // WIN_PLATFORM

void default_log_handler( unsigned long u32MsgType, char * pLogMsg );
void vx_error( unsigned long u32MsgType, const char* msg, ...);

LOG_FUNCTION g_pfuncLogHandler = default_log_handler;

static unsigned long g_u32LogFlags = 0xffffffff;
static char g_as8LogFileName[MAX_PATH] = {0};
static int g_iLogNameLen = 0;
VxMutex g_oFileLogMutex;

//============================================================================--
void log_to_file( const char * pFileName, const char * pMsg )
{
static bool firstLog = true;
	if( false == VxIsAppShuttingDown() )
	{
		if(pMsg)
		{
			int iMsgLen = strlen( pMsg );
			g_oFileLogMutex.Lock();
			if( firstLog )
			{
				#ifdef WIN_PLATFORM
					_unlink( pFileName );
				#else // LINUX
					unlink( pFileName );
				#endif // LINUX
				firstLog = false;
			}
			FILE * poFile = fopen( pFileName, "ab+" );
			if( poFile )
			{ 
				fwrite( pMsg, iMsgLen, 1, poFile );
				fclose( poFile );
			}
			g_oFileLogMutex.Unlock();
		}
	}
}

//============================================================================--
void set_log_to_file( const char * pFileName )
{
	int strLen = strlen( g_as8LogFileName );
	if( (0 == g_iLogNameLen) && strLen )
	{
		// first time we set the log file delete any previous so we
		// dont keep filling up the log
		VxDeleteFile( pFileName );
	}
	g_iLogNameLen = strLen;
    strcpy( g_as8LogFileName, pFileName );
    
}

//============================================================================--
void set_log_flags( unsigned long u32LogFlags )
{
	g_u32LogFlags = u32LogFlags;
}

//============================================================================--
/// This function sets the handler of log messages
void set_log_handler( LOG_FUNCTION pfuncLogHandler )
{
	g_pfuncLogHandler = pfuncLogHandler;
}

//============================================================================--
/// This function is called by vx_assert() when the assertion fails.
void  vx_error_output( unsigned long u32MsgType, char* exp, char * file, int line)
{
    vx_error(u32MsgType, "** RT ASSERTION **\r\nexpression: %s\r\nfile: %s\r\nline: %d\r\n", exp, file, line);
}

//============================================================================--
/// This function is called by vx_assert2() when the assertion fails.
void vx_error_output2(unsigned long u32MsgType, char* exp,  char* msg, char* file, int line)
{
    vx_error(u32MsgType, "** RT ASSERTION ***\r\nprogrammer says: %s\r\nexpression: %s\r\nfile: %s\r\nline: %d\r\n", msg, exp, file, line);
}

//============================================================================--
/// This function is called when a serious situation is encountered which
/// requires abortion of the program.
void vx_error( unsigned long u32MsgType, const char* msg, ...)
{
	char as8Buf[ MAX_ERR_MSG_SIZE * 2 ];
    va_list argList;
    va_start(argList, msg);
	vsnprintf( as8Buf, sizeof( as8Buf ), msg, argList );
	as8Buf[sizeof( as8Buf ) - 1] = 0;
    va_end(argList);

	log_msg( u32MsgType,  as8Buf ); // send to log
	if( LOG_FATAL == u32MsgType )
	{
		//exit(99);
	}
};
//============================================================================--
/// default log handler
void default_log_handler( unsigned long u32MsgType, char * pLogMsg )
{
	u32MsgType = (u32MsgType & LOG_PRIORITY_MASK);
	//if( u32MsgType > g_u32LogLevel )
	//{
	//	return; // dont log
	//}
#ifdef ANDROID_PLATFORM
#define MY_LOG_TAG "com.roguetreasure.destroytheworld"
	switch( u32MsgType )
	{
	case LOG_INFO:
		__android_log_write(ANDROID_LOG_INFO, MY_LOG_TAG, pLogMsg);
		break;
	case LOG_FATAL:
	case LOG_ASSERT:
	case LOG_ERROR:
		__android_log_write(ANDROID_LOG_ERROR, MY_LOG_TAG, pLogMsg);
		break;
	case LOG_WARN:
		__android_log_write(ANDROID_LOG_WARN, MY_LOG_TAG, pLogMsg);
		break;
	case LOG_VERBOSE:
		__android_log_write(ANDROID_LOG_VERBOSE, MY_LOG_TAG, pLogMsg);
		break;
	default:
		__android_log_write(ANDROID_LOG_DEBUG, MY_LOG_TAG, pLogMsg);
	}
#else
	printf( pLogMsg );
#endif// ANDROID_PLATFORM
}
//============================================================================--
/// log a message
void log_msg( unsigned long u32MsgType, const char* msg, ... )
{
	char as8Buf[ MAX_ERR_MSG_SIZE ];
    va_list argList;
    va_start(argList, msg);
	if( 0 == u32MsgType )
	{
		u32MsgType = LOG_DEBUG; 
	}
	if( 0 == ( g_u32LogFlags && u32MsgType ) )
	{
		return; // dont log
	}
	u32MsgType = u32MsgType && LOG_PRIORITY_MASK;
	if( 0 == u32MsgType )
	{
		u32MsgType = LOG_DEBUG;
	}
	vsnprintf( as8Buf, sizeof( as8Buf ), msg, argList );
	as8Buf[sizeof( as8Buf ) - 1] = 0;
    va_end(argList);
	#ifdef WIN_PLATFORM
		OutputDebugStringA(as8Buf);
	#endif // WIN_PLATFORM
    if( g_iLogNameLen )
	{
        log_to_file( g_as8LogFileName, as8Buf );
	}
	// send to log handler
	g_pfuncLogHandler( u32MsgType, as8Buf );
}
